#pragma once 
#include<iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string>
#include <unordered_map>
#include <memory>

#include "InetAddr.hpp"
#include "Log.hpp"
#include "Mutex.hpp"

using namespace LogMoudle;
using namespace MutexMoudle;

// 接口类  观察者抽象类
class UserInterface    
{
public:
    virtual ~UserInterface() =default;
    virtual std::string Id() =0;
    virtual void SendTo(int sockfd,const std::string& message) =0;
    virtual bool operator==(const InetAddr& u)=0;
};

// 具体的观察者
class User :public UserInterface   
{
public:
    User(const InetAddr& id) :_id(id){}
    ~User(){}
    std::string Id() {return _id.Addr();}
    void SendTo(int sockfd,const std::string& message)
    {
        LOG(LogLevel::DEBUG)<<"send message to "<<Id()<<" info: "<<message;
        int n=sendto(sockfd,message.c_str(),message.size(),0,_id.Netaddr_ptr(),_id.Netaddrlen());
        if(n<0)
        LOG(LogLevel::FATAL)<<"SendTo error";
    }
    bool operator==(const InetAddr& u)
    {
        return _id==u; 
    }
private:
    InetAddr _id;
};

// 对用户消息进行路由
// UserManager 把所有的用户先管理起来！
// 观察者模式！ observe
// 具体的主题类
class UserManager
{
  public:
        UserManager(){}
        ~UserManager(){}
        void AddUser(const InetAddr& id )
        {
            LockGuard lock(_mutex);
            if(_online_user.count(id))
            {
                LOG(LogLevel::DEBUG)<<id.Addr()<<" 用户已存在...";
                return ;
            }
            _online_user.insert({id,std::make_shared<User>(id)});
            LOG(LogLevel::DEBUG)<<"新添加用户: "<<id.Addr();
            PrintUser(); 
        }
        void DelUser(const InetAddr& id)
        {
            LockGuard lock(_mutex);
            _online_user.erase(id);
            LOG(LogLevel::DEBUG)<<"删除用户: "<<id.Addr();
            PrintUser();
        }
        void Router(int sockfd,const std::string& message)
        {
             // 正是因为每次转发都需要遍历，所以观察者的个数是有上限的，这也是为什么我们聊天软件里群成员的个数也是有限的。
            for(auto& [inetaddr,user]:_online_user)  
            {
                user->SendTo(sockfd,message);
            }
        }
        void PrintUser()
        {
            for(auto& [inetaddr,user]:_online_user)
            {
                LOG(LogLevel::DEBUG)<<"在线用户: "<<inetaddr.Addr();
            }
        }
  private:
    std::unordered_map<InetAddr,std::shared_ptr<UserInterface>> _online_user;
    Mutex _mutex;    //AddUser和DelUser 对临界区的增加与删除，需要加锁保护
};